#include <SDL/SDL.h>
#include <fstream>
#include <wx/utils.h>

#include "headers/Windows.h"


extern SDL_Surface* screen;

/**************************************
************ Draw Object **************
**************************************/

/* Normal constructor */
Window::Window(const char* name, int style, int size_w, int size_h, int (*MClick)(int,int,int)):
    Name(name), 
    Style(style),
    w(size_w), h(size_h),
    wDest(size_w), hDest(size_h),
    MouseClick(MClick),
    xSrc(0), ySrc(0),
    xDest(0), yDest(0),
    DrawingMode(Normal) {

    SurfaceBackground = SDL_CreateRGBSurface( SDL_ANYFORMAT, 
                                              w, h, 
                                              screen->format->BitsPerPixel,
                                              screen->format->Rmask, 
                                              screen->format->Gmask, 
                                              screen->format->Bmask, 
                                              screen->format->Amask);
                                              
    SurfaceAll = SDL_CreateRGBSurface( SDL_ANYFORMAT, 
                                       w, h, 
                                       screen->format->BitsPerPixel,
                                       screen->format->Rmask, 
                                       screen->format->Gmask, 
                                       screen->format->Bmask, 
                                       screen->format->Amask);
                                       
    Surface = SurfaceAll;
}

/* Copy constructor */
Window::Window(const Window& W):
    Style(W.Style),
    w(W.w), h(W.h),
    xSrc(W.xSrc), ySrc(W.ySrc),
    xDest(W.xDest), yDest(W.yDest),
    wDest(W.wDest), hDest(W.hDest),
    Name(W.Name),
    MouseClick(W.MouseClick),
    DrawingMode(W.DrawingMode) {
        
    SurfaceBackground = SDL_CreateRGBSurface( SDL_ANYFORMAT, 
                                              w, h, 
                                              screen->format->BitsPerPixel,
                                              screen->format->Rmask, 
                                              screen->format->Gmask, 
                                              screen->format->Bmask, 
                                              screen->format->Amask);
                                              
    SurfaceAll = SDL_CreateRGBSurface( SDL_ANYFORMAT, 
                                       w, h, 
                                       screen->format->BitsPerPixel,
                                       screen->format->Rmask, 
                                       screen->format->Gmask, 
                                       screen->format->Bmask, 
                                       screen->format->Amask);
                                    
    SDL_Rect Rect;
    
    Rect.x = 0; Rect.y = 0;
    Rect.w = w; Rect.h = h;
    
    /* Copy surfaces */
    SDL_UpperBlit(W.SurfaceBackground, &Rect, SurfaceBackground, &Rect);
    SDL_UpperBlit(W.SurfaceAll, &Rect, SurfaceAll, &Rect);
    
    if (DrawingMode == 0) Surface = SurfaceBackground;
    else
        Surface = SurfaceAll;
} 

int Window::Resize(int size_w, int size_h) {
    
    SDL_Surface* SurfaceBgTmp;
    SDL_Surface* SurfaceAllTmp;
    
    if (size_w<wDest) size_w=wDest;
    if (size_h<hDest) size_h=hDest;
    
    /* Create resized surfaces */
    SurfaceBgTmp = SDL_CreateRGBSurface( SDL_ANYFORMAT,
                                         size_w, size_h,
                                         screen->format->BitsPerPixel,
                                         screen->format->Rmask, 
                                         screen->format->Gmask, 
                                         screen->format->Bmask, 
                                         screen->format->Amask);
    SurfaceAllTmp = SDL_CreateRGBSurface( SDL_ANYFORMAT,
                                          size_w, size_h,
                                          screen->format->BitsPerPixel,
                                          screen->format->Rmask, 
                                          screen->format->Gmask, 
                                          screen->format->Bmask, 
                                          screen->format->Amask);
                                       
    SDL_Rect RectSrc;
    SDL_Rect RectDst;
    
    RectSrc.x = 0;
    RectSrc.y = 0;
    RectSrc.w = size_w > w ? w : size_w;
    RectSrc.h = size_h > h ? h : size_h;
    
    RectDst.x = 0;
    RectDst.y = 0;
    RectDst.w = RectSrc.w;
    RectDst.h = RectSrc.h;
    
    /* Copy surfaces */
    SDL_UpperBlit(SurfaceBackground, &RectSrc, SurfaceBgTmp, &RectDst);
    SDL_UpperBlit(SurfaceAll, &RectSrc, SurfaceAllTmp, &RectDst);
    
    /* Delete old surfaces*/
    SDL_FreeSurface(SurfaceBackground);
    SDL_FreeSurface(SurfaceAll);
    SurfaceBackground = SurfaceBgTmp;
    SurfaceAll = SurfaceAllTmp;
    w = size_w;
    h = size_h;
    
    if (DrawingMode == 0) Surface = SurfaceBackground;
    else
        Surface = SurfaceAll;
}


int Window::Clear() {
    
    int _w, _h;
    
    _w = w>wDest ? w:wDest;
    _h = h>hDest ? h:hDest;
    
    SDL_Surface *Black =  SDL_CreateRGBSurface( SDL_ANYFORMAT, 
                                                _w, _h, 
                                                screen->format->BitsPerPixel,
                                                screen->format->Rmask, 
                                                screen->format->Gmask, 
                                                screen->format->Bmask, 
                                                screen->format->Amask);
    
    SDL_Rect r;
    r.x = 0;
    r.y = 0;
    r.w = _w;
    r.h = _h;
                                               
    SDL_BlitSurface(Black, &r, SurfaceBackground, &r);
    SDL_BlitSurface(Black, &r, SurfaceAll, &r);
    
}
    

/*********************************
********** Draw Menager **********
*********************************/


/* Public */


int WindowsMenager::AddWindow(const char* name, int style, int w, int h, int (*MClick)(int,int,int)) {
    return MakeWindow(name, style, w, h, MClick);
};

int WindowsMenager::AddWindow(const char* name, int style, int (*MClick)(int,int,int)) {
    return MakeWindow(name, style, 0, 0, MClick);
};

int WindowsMenager::AddWindow(const char* name) {
    return MakeWindow(name, 0, 0, 0, NULL);
}

int WindowsMenager::Resize(const char* name, int w, int h) {
    
    int id = Search(name);
    if (id>=0) 
        vWindows[id].Resize(w, h);
        
}

int WindowsMenager::DrawPixel(const char* name, int color, int x, int y, int w, int h) {

    SDL_Rect r;
    
    r.x = x;
    r.y = y;
    r.w = w;
    r.h = h;
       
        
    int id = Search(name);
    if (id>=0) {
        SDL_FillRect(vWindows[id].Surface, &r, color);
        if (vWindows[id].DrawingMode == 1)
            vWindows[id].vPixels.push_back(Pixel(x,y,w,h));
        else
            SDL_FillRect(vWindows[id].SurfaceAll, &r, color);
            
    }
            
        
    
}

int WindowsMenager::MouseClick(int x, int y, int b) {

    for (int i=0; i<vWindows.size(); i++) {
        Window* w;
        w = &vWindows[i];
        
        if ((w->xDest<=x) && ((w->xDest+w->wDest)>=x) && (w->yDest<=y) && ((w->yDest+w->hDest)>=y)) {
            w->MouseClick( x - w->xDest + w->xSrc,
                           y - w->yDest + w->ySrc,
                           b );
            break;
        }
        

        if (w->Style & FRAME_DOWN) {
            if ( (w->xDest<=x) && (w->xDest+10>=x) && (w->yDest+w->hDest<=y) && (w->yDest+w->hDest+10>=y)) {       
                w->Buttons.DownL.pressed=1;
                break;
            }
            if ( (w->xDest+w->wDest-10<=x) && (w->xDest+w->wDest>=x) && (w->yDest+w->hDest<=y) && (w->yDest+w->hDest+10>=y)) {       
                w->Buttons.DownR.pressed=1;
                break;
            }
        }
        
        if (w->Style & FRAME_RIGHT) {
            if ( (w->yDest<=y) && (w->yDest+10>=y) && (w->xDest+w->wDest<=x) && (w->xDest+w->wDest+10>=x)) {       
                w->Buttons.RightU.pressed=1;
                break;
            }
            if ( (w->yDest+w->hDest-10<=y) && (w->yDest+w->hDest>=y) && (w->xDest+w->wDest<=x) && (w->xDest+w->wDest+10>=x)) {      
                w->Buttons.RightD.pressed=1;
                break;
            }
        }                         
    }
}

int WindowsMenager::MouseUp() {
    
    for (int i=0; i<vWindows.size(); i++) {
        if (vWindows[i].Buttons.DownR.pressed) {
            vWindows[i].Buttons.DownR.pressed = 0;
            break;
        }
        if (vWindows[i].Buttons.DownL.pressed) {
            vWindows[i].Buttons.DownL.pressed = 0;
            break;
        }
        if (vWindows[i].Buttons.RightU.pressed) {
            vWindows[i].Buttons.RightU.pressed = 0;
            break;
        }
        if (vWindows[i].Buttons.RightD.pressed) {
            vWindows[i].Buttons.RightD.pressed = 0;
            break;
        }
    }
}

int WindowsMenager::IsMouseOnWindow(const char* name) {

    int x;
    int y;
    
    int id = Search(name);
    if (id>=0) {
        Window* w;
        w = &vWindows[id];
    
        wxGetMousePosition(&x, &y);
    
        if (x>=w->xDest && x<=w->xDest+w->wDest &&
              y>=w->yDest && y<=w->yDest+w->hDest)
            return 1;
    }
    
    return 0;
}
        
extern int GetMousePosition(int* x, int* y);

int WindowsMenager::GetMouseState(const char* name, int* x, int* y) {

    int id = Search(name);
    if (id>=0) {
        Window* w;
        w = &vWindows[id];
        
        GetMousePosition(x, y);      
        
        *x = *x - w->xDest + w->xSrc;
        *y = *y - w->yDest + w->ySrc;                             
    } else {
        *x = 0;
        *y = 0;
    }
       
}    
          
    
int WindowsMenager::DrawAll() {
       
    SDL_Rect RectSrc;
    SDL_Rect RectDst;
    SDL_Rect R;
    
    Window* w;

    for(int i=0; i<vWindows.size(); i++) {
        
        w = &vWindows[i];
        
        RectSrc.x = w->xSrc;
        RectSrc.y = w->ySrc;
        RectSrc.w = w->wDest;
        RectSrc.h = w->hDest;
        
        RectDst.x = w->xDest;
        RectDst.y = w->yDest;
        RectDst.w = RectSrc.w;
        RectDst.h = RectSrc.h;
               
        SDL_UpperBlit(w->Surface, &RectSrc, screen, &RectDst);
        
        /* Draw frames and buttons : */
        
        /* Frame down : */       
        if (vWindows[i].Style & FRAME_DOWN) {
            
            int LeftButton = w->Buttons.DownL.pressed;
            int RightButton = w->Buttons.DownR.pressed;
            
            if (LeftButton) {
                w->xSrc-=5;
                if (w->xSrc < 0)
                    w->xSrc=0;
            } else
            if (RightButton) {
                w->xSrc+=5;
                if (w->xSrc > (w->w - w->wDest))
                    w->xSrc = w->w - w->wDest;
            }
            
            R.x = RectDst.x+10;
            R.y = RectDst.y + RectDst.h;
            R.w = RectDst.w-20;
            R.h = 1;
            
            for(int j=10; j>0; j--) {
                SDL_FillRect(screen, &R, GetRGB(180, 180, 180));
                R.y++;
            }
            
            int BarH;
            float BarX;
            
            if (w->w - w->wDest > 0) {
                BarH = RectDst.w - 20 - (w->w - w->wDest)*2;
                if (BarH<16) BarH = 16;
                BarX = (float)w->xSrc / (w->w - w->wDest);
            
                BarX *= w->wDest - 20 - BarH;
                BarX+=10;
                
                if (BarX > w->wDest - 10 - BarH)
                    BarX = w->wDest - 10 - BarH;
            } else {
                BarH = RectDst.w - 20;
                BarX = 10;
            }
            
            R.x = w->xDest + int(BarX);
            R.y = RectDst.y + RectDst.h;
            R.w = BarH;
            R.h = 1;
            
            for(int j=10; j>0; j--) {
                SDL_FillRect(screen, &R, GetRGB(50+j*20,50+j*20,50+j*20));
                R.y++;
            }
            
            
            R.y = RectDst.y + RectDst.h;
            R.w = 2;
            R.h = 1;    
            for(int k=0; k<10; k++) {
                R.x = RectDst.x;       
                for(int j=0; j<5; j++) { 
                    SDL_FillRect(screen, &R, GetRGB( 200-j*20-k*10, 200-j*20-k*10, LeftButton ? 0 : 255-k*10 ));
                    R.x+=2;
                }
                R.y++;
            }   
            
            R.y = RectDst.y + RectDst.h;
            R.w = 2;
            R.h = 1;
            for(int k=0; k<10; k++) {
                R.x = RectDst.x + RectDst.w - 10;        
                for(int j=4; j>=0; j--) { 
                    SDL_FillRect(screen, &R, GetRGB( 200-j*20-k*10,200-j*20 -k*10, RightButton ? 0 : 255-k*10 ));
                    R.x+=2;
                }
                R.y++;
            }                                       
        }
        
        if (w->Style & FRAME_RIGHT) {
            
            int UpButton = vWindows[i].Buttons.RightU.pressed;
            int DownButton = vWindows[i].Buttons.RightD.pressed;
            
            if (UpButton==1) {
                w->ySrc-=5;
                if (w->ySrc<0)
                    w->ySrc=0;
            } else
            if (DownButton==1) {
                w->ySrc+=5;
                if (w->ySrc>(w->h - w->hDest))
                    w->ySrc = w->h - w->hDest;
            }
            
            R.x = RectDst.x + RectDst.w;
            R.y = RectDst.y;
            R.w = 1;
            R.h = RectDst.h;
            
            for(int j=10; j>0; j--) {
                SDL_FillRect(screen, &R, GetRGB(50+j*20,50+j*20,50+j*20));
                R.x++;
            }
            
            R.x = RectDst.x + RectDst.w;
            R.y = RectDst.y;
            R.w = 1;
            R.h = 2;
            for(int k=0; k<10; k++) {
                R.y = RectDst.y;       
                for(int j=0; j<5; j++) {
                    SDL_FillRect(screen, &R, GetRGB( 200-j*20-k*10, 200-j*20-k*10, UpButton ? 0 : 255-k*10 ));
                    R.y+=2;
                }
                R.x++;
            }
               
            R.x = RectDst.x + RectDst.w;
            R.y = RectDst.y + RectDst.h - 10;
            R.w = 1;
            R.h = 2;
            for(int k=0; k<10; k++) {
                R.y = RectDst.y + RectDst.h - 10; 
                for(int j=4; j>=0; j--) {
                    SDL_FillRect(screen, &R, GetRGB( 200-j*20-k*10, 200-j*20-k*10, DownButton ? 0 : 255-k*10 ));
                    R.y+=2;
                }
                R.x++;
            }   
        }

        
        for (int j=0; j<w->vPixels.size(); j++) {
            R.x = w->vPixels[j].x;
            R.y = w->vPixels[j].y;
            R.w = w->vPixels[j].w;
            R.h = w->vPixels[j].h;
            
            SDL_UpperBlit(vWindows[i].SurfaceBackground, &R, vWindows[i].SurfaceAll , &R);
        }    
        w->vPixels.clear();
        
    }
    
    /* Time for frames: */
    Time-=1;
    if (Time>8) Time = 8;
    if (Time<=0) Time = 8;
}

int WindowsMenager::DrawFrame(const char* name, int color, int x, int y, int w, int h) {

    int TimeCur = int(Time);
      
    for (int i=0; i<w; i++, TimeCur++) {
        if (TimeCur>7) TimeCur = 0;
        if (TimeCur<4)
            DrawPixel(name, color, x+i, y);
    }
    for (int i=1; i<h; i++, TimeCur++) {
        if (TimeCur>7) TimeCur = 0;
        if (TimeCur<4)
            DrawPixel(name, color, x+(w-1), y+i);
    }
    for (int i=w-2; i>=0; i--, TimeCur++) {
        if (TimeCur>7) TimeCur = 0;
        if (TimeCur<4)
            DrawPixel(name, color, x+i, y+(h-1));
    }
    for (int i=h-2; i>=1; i--, TimeCur++) {
        if (TimeCur>7) TimeCur = 0;
        if (TimeCur<4)
            DrawPixel(name, color, x, y+i);
    }
}


int WindowsMenager::GetW(const char* name) {
    int id = Search(name);
    if (id>=0) 
        return vWindows[id].w;
}

int WindowsMenager::GetH(const char* name) {
    int id = Search(name);
    if (id>=0)
        return vWindows[id].h;
}

       
int WindowsMenager::SetSrcX(const char* name, int x) {
    int id = Search(name);
    if (id>=0)
        vWindows[id].xSrc = x;

}

int WindowsMenager::SetSrcY(const char* name, int y) {
    int id = Search(name);
    if (id>=0) 
        vWindows[id].ySrc = y;
}

int WindowsMenager::SetDestX(const char* name, int x) {
    int id = Search(name);
    if (id>=0) 
        vWindows[id].xDest = x;
}

int WindowsMenager::SetDestY(const char* name, int y) {
    int id = Search(name);
    if (id>=0) 
        vWindows[id].yDest = y;
}

int WindowsMenager::SetDestW(const char* name, int w) {
    int id = Search(name);
    if (id>=0) 
        vWindows[id].wDest = w;
}

int WindowsMenager::SetDestH(const char* name, int h) {
    int id = Search(name);
    if (id>=0) 
        vWindows[id].hDest = h;

}

int WindowsMenager::StartDrawingBackground(const char* name) {
    int id = Search(name);
    if (id>=0) {
        vWindows[id].Surface = vWindows[id].SurfaceBackground;
        vWindows[id].DrawingMode = Background;
    }
}

int WindowsMenager::StopDrawingBackground(const char* name) {
    int id = Search(name);
    if (id>=0) {
        vWindows[id].Surface = vWindows[id].SurfaceAll;
        vWindows[id].DrawingMode = Normal;
    }
}

int WindowsMenager::Clear() {
    
    SDL_Surface *Black =  SDL_CreateRGBSurface( SDL_ANYFORMAT, 
                                                640, 460, 
                                                screen->format->BitsPerPixel,
                                                screen->format->Rmask, 
                                                screen->format->Gmask, 
                                                screen->format->Bmask, 
                                                screen->format->Amask);
    
    SDL_Rect dest;
    dest.x = 0;
    dest.y = 0;
                                               
    SDL_BlitSurface(Black, NULL, screen, &dest);    

}

int WindowsMenager::Clear(int x, int y, int w, int h) {
    
    SDL_Surface *Black =  SDL_CreateRGBSurface( SDL_ANYFORMAT, 
                                                w, h, 
                                                screen->format->BitsPerPixel,
                                                screen->format->Rmask, 
                                                screen->format->Gmask, 
                                                screen->format->Bmask, 
                                                screen->format->Amask);
    
    SDL_Rect dest;
    dest.x = x;
    dest.y = y;
                                               
    SDL_BlitSurface(Black, NULL, screen, &dest);    

}

int WindowsMenager::Clear(const char* name) {

    int id = Search(name);
    if (id>=0) {
        vWindows[id].Clear();
        return id;
    }
    
}
    
/* Private */


int WindowsMenager::MakeWindow(const char* name, int style, int w, int h, int (*MClick)(int,int,int)) {
    
    int id = Search(name);
    if (id>=0) {
        Resize(name, w, h);
        vWindows[id].MouseClick = MClick;
        return id;
    }

    
    vWindows.push_back(Window(name, style, w, h, MClick));
    return vWindows.size()-1;
    
}


int WindowsMenager::Search(const char* name) {
    
    for (int i=0; i<vWindows.size(); i++)
        if (!vWindows[i].Name.compare(name))
            return i;
                       
    return -1;
}
             
    
  

        

        
